﻿/*
 * 操作缓存数据库Redis
 * 1、安装依赖包  CSRedisCore
 * 2、它也是数据库，所以需要连接到这个redis数据库
 * 
 * 
 * **/


using Max.PH5_2006.ShoppingSite.IService;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Max.PH5_2006.ShoppingSite.DemoAPI.Controllers
{
    [Route("car")]
    [ApiController]
    public class CarController : ControllerBase
    {

        IGoodsService _goodsService;
        IStoreService _storeService;


        //定义为全局变量，在这个类的方法中，都可以使用这个变量
        CSRedis.CSRedisClient _redis;
        NLog.Logger _log;

        /// <summary>
        /// 构造函数（作用：初始化值）
        /// </summary>
        public CarController(IGoodsService goodsService, IStoreService storeService)
        {
            _goodsService = goodsService;
            _storeService = storeService;

            //连接到redis数据库,获取到redis的客户端对象
            _redis =  new CSRedis.CSRedisClient("127.0.0.1:6379");

            _log =  NLog.LogManager.GetCurrentClassLogger();
        }

        #region 购物车常规操作

        /// <summary>
        /// 获取购物车列表数据
        /// </summary>
        /// <param name="key">表示redis拿谁的数据--- 这个谁，就是用key来区分</param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetCar(string key)
        {
            if(!_redis.Exists(key))
                return Ok(new { statue = false,msg="key不存在"});

            //默认.Get返回的是字符串。
            //var data = _redis.Get(key); 

            //但是我们每个人的购物车中，有可能会放多个商品（商品品种一样，数量也不一样） --- 所以在redis购物车中，每个人的购物车，应该是一个集合形式
            var data = _redis.Get<List<CarDemoEntity>>(key);

            return Ok(new { statue = true, data });
        }

        /// <summary>
        /// 添加商品到购物车
        /// </summary>
        /// <param name="entity">需要一个key，还需要一个商品信息[商品id，商品名称，商品数量，商品价格] 。CarDemoEntity对象包含了这些</param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult AddCar(CarDemoEntity entity)
        {
            string key = entity.MemberId;

            if(!_redis.Exists(key))
            {
                //redis中不存在这个key,那么说明是第一个使用，集合是null的，需要new一个，然后直接放进集合

                var list = new List<CarDemoEntity>();
                list.Add(entity);

                _redis.Set(key, list);
            }
            else
            {
                var list = _redis.Get<List<CarDemoEntity>>(key);

                //判断是否添加的是同一个商品
                var m = list.Where(x => x.GoodsId.Equals(entity.GoodsId)).FirstOrDefault();
                if(m != null)
                {
                    //是同一个商品，那么，只需要修改数量
                    m.GoodsCount += entity.GoodsCount;
                }
                else
                {
                    //不是同一个商品，那么直接放进集合里 
                    list.Add(entity);
                }

                _redis.Set(key, list);  //最后更新缓存
            }

            return Ok(0);
        }

        /// <summary>
        /// 删除购物车(单删除和批量删除都这一个方法即可)
        /// </summary>
        /// <param name="entities">需要一个key，还需要删除的哪个商品。 我们的CarDemoEnityt对象都包含了这两个参数（批量删除：则是多个商品）</param>
        /// <returns></returns>
        [HttpDelete]
        public IActionResult DeleteCar(List<CarDemoEntity> entities)
        {
            //CarDemoEntity对象中，会员ID都是一样的，所以随便哪一条的memberid都可以
            string key = entities[0].MemberId;

            //删除：是删除购物车列表中的数据（即缓存redis里的数据）
            //所以：要先拿到缓存里的数据
            var data = _redis.Get<List<CarDemoEntity>>(key);

            //然后去这缓存里找到要删除的商品，找到了就删除，没找到，就不管
            //因为要删除的商品（单删是一个，批量删除是多个），所以循环
            entities.ForEach(x =>
            {
                //循环一个一个去缓存数据库里找
                var m = data.Where(p => p.GoodsId.Equals(x.GoodsId)).FirstOrDefault();

                if(m!=null)  //不等于null，说明缓存数据库里有要删除的这个商品，那么直接从缓存数据库里删除即可
                {
                    data.Remove(m);
                    _log.Info($"{System.DateTime.Now} 从缓存里删除商品id={m.GoodsId}的商品");
                }                
            });

            //执行完成之后，记得更新到缓存（因为缓存数据里删除过数据）
            _redis.Set(key, data);

            return Ok();
        }

        #endregion

        #region 购物车店铺分组显示


        /// <summary>
        /// 购物车店铺分组显示
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        [HttpGet("store")]
        public IActionResult GetStoreCar(string key)
        {
            //1、先获取购物车的商品数据
            var data = _redis.Get<List<CarDemoEntity>>(key);

            //2、通过商品数据，就知道这个商品是属于哪个店铺的。
            //（我的购物车CarDemoEntity中，没有存放店铺ID，所以需要通过商品表GoodsEntity来查询购物车中的商品属性于哪个店铺）,如果购物车中存放了店铺ID，就不用查啦。

            var goods = _goodsService.Query();
            var store = _storeService.Query();

            //根建商品是属于哪家店铺（用商品Id 通过关联商品表，用店铺ID，通过关联店铺表）
            var u = from d in data
            join g in goods on d.GoodsId equals g.Id.ToString()
            join s in store on g.StoreId equals s.Id            
            select new
            {
                d.MemberId,
                d.GoodsId,
                d.GoodsName,
                d.GoodsPrice,
                GoodsNumber = d.GoodsCount,
                StoreId = s.Id,
                StoreName = s.Name
            };

            //在刚才上一步查出来的数据中，对店铺进行分组，并把对应的商品放到它店铺的items中               
            var f = from a in u
            group a by new { a.StoreId, a.StoreName } into k
            select new
            {
                StoreId = k.Key.StoreId,
                StoreName = k.Key.StoreName,
                Items = k
            };
         
            return Ok(f);
        }

        #endregion
    }

    public class CarDemoEntity
    {
        public string? MemberId { get; set; }
        public string? GoodsId { get; set; }
        public string? GoodsName { get; set; }
        public decimal? GoodsPrice { get; set; }
        public int? GoodsCount { get; set; }
    }
}
